// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SortableBindingList.cs" company="GT">
//   Gunther Taborga
// </copyright>
// <summary>
//   Defines the SortableBindingList type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace BatchID3.Lists
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;

    public class SortableBindingList<T> : BindingList<T>, IBindingList
    {
        private readonly Dictionary<Type, PropertyComparer<T>> comparers;

        private bool isSorted;

        private ListSortDirection listSortDirection;

        private PropertyDescriptor propertyDescriptor;

        public SortableBindingList()
            : base(new List<T>())
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        public SortableBindingList(IEnumerable<T> enumeration)
            : base(new List<T>(enumeration))
        {
            this.comparers = new Dictionary<Type, PropertyComparer<T>>();
        }

        protected override bool IsSortedCore
        {
            get
            {
                return this.isSorted;
            }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get
            {
                return this.listSortDirection;
            }
        }

        protected override PropertyDescriptor SortPropertyCore
        {
            get
            {
                return this.propertyDescriptor;
            }
        }

        protected override bool SupportsSearchingCore
        {
            get
            {
                return true;
            }
        }

        protected override bool SupportsSortingCore
        {
            get
            {
                return true;
            }
        }

        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
        {
            var itemsList = (List<T>)this.Items;

            Type propertyType = property.PropertyType;
            PropertyComparer<T> comparer;

            if (!this.comparers.TryGetValue(propertyType, out comparer))
            {
                comparer = new PropertyComparer<T>(property, direction);
                this.comparers.Add(propertyType, comparer);
            }

            comparer.SetPropertyAndDirection(property, direction);
            itemsList.Sort(comparer);

            this.propertyDescriptor = property;
            this.listSortDirection = direction;
            this.isSorted = true;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        protected override int FindCore(PropertyDescriptor property, object key)
        {
            if (property != null)
            {
                int count = this.Count;
                for (int i = 0; i < count; ++i)
                {
                    T element = this[i];
                    var value = property.GetValue(element);
                    if (value != null && value.Equals(key))
                    {
                        return i;
                    }
                }
            }
            
            return -1;
        }

        protected override void RemoveSortCore()
        {
            this.isSorted = false;
            this.propertyDescriptor = base.SortPropertyCore;
            this.listSortDirection = base.SortDirectionCore;

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
    }
}